#ifndef BI_BIGINTEGER_HPP
#define BI_BIGINTEGER_HPP

#include <memory>
#include <string>

namespace bi {

	class BigInteger {
	public:
		BigInteger();
		BigInteger( const BigInteger & that );
		BigInteger( BigInteger && that );
		BigInteger( int i );
		BigInteger( long l );
		BigInteger( const char * c );
		BigInteger( const std::string & s );
		~BigInteger();

		BigInteger & operator =( const BigInteger & that );
		BigInteger & operator =( BigInteger && that );

		BigInteger & operator +=( const BigInteger & that );
		BigInteger & operator -=( const BigInteger & that );

		BigInteger operator -() const;

		template< typename T >
		T to() const;
	private:
		friend bool operator <( const BigInteger & a, const BigInteger & b );
		friend bool operator ==( const BigInteger & a, const BigInteger & b );
		friend std::istream & operator >>( std::istream & in, BigInteger & self );
		friend std::ostream & operator <<( std::ostream & out, const BigInteger & self );
		class Private;
		std::unique_ptr< Private > p_;
	};

	bool operator <( const BigInteger & a, const BigInteger & b );
	bool operator <=( const BigInteger & a, const BigInteger & b );
	bool operator ==( const BigInteger & a, const BigInteger & b );
	bool operator >=( const BigInteger & a, const BigInteger & b );
	bool operator >( const BigInteger & a, const BigInteger & b );
	bool operator !=( const BigInteger & a, const BigInteger & b );

	BigInteger operator +( const BigInteger & a, const BigInteger & b );
	BigInteger operator +( const BigInteger & a, BigInteger && b );
	BigInteger operator +( BigInteger && a, const BigInteger & b );
	BigInteger operator +( BigInteger & a, BigInteger && b );
	BigInteger operator -( const BigInteger & a, const BigInteger & b );
	BigInteger operator -( const BigInteger & a, BigInteger && b );
	BigInteger operator -( BigInteger && a, const BigInteger & b );
	BigInteger operator -( BigInteger && a, BigInteger && b );

	std::istream & operator >>( std::istream & in, BigInteger & self );
	std::ostream & operator <<( std::ostream & out, const BigInteger & self );

}

#endif
